
  {COMMAND.PA2}

  {              READ_INSTRUCTIONS}
  {Read INSTRUCTIONS file (if it exists) and display it}

  PROCEDURE Read_INSTRUCTIONS;

  LABEL Exit;
  VAR
    sentence, Answer : s;
    fname : words;
    LineCount : Integer;

  BEGIN                           {read_instructions}
    fname := Instruction_File_Name;
    IF NOT File_Exists(fname) THEN GOTO Exit;
    Write(IO, 'Would you like to read the instructions ? ');
    Answer := GetInputString;
    Answer := Upcase(Answer[1]);
    IF Answer = 'N' THEN GOTO Exit;
    CLRSCR;                       {start with clean slate}
    LineCount := 0;
    Assign(datafile, Instruction_File_Name);
    Reset(datafile);
    REPEAT                        {until (sentence = 'END OF FILE') or (EOF(datafile))}
      LineCount := LineCount+1;
      IF LineCount = 22 THEN
        BEGIN
          Pause;
          LineCount := 0;         {start over}
        END;
      ReadLn(datafile, sentence);
      WriteLn(IO, sentence);
    UNTIL (POS('END OF FILE', sentence) <> 0) OR (EOF(datafile));
    Pause;                        {when done reading instructions}
Exit:
    CLRSCR;                       {clear before showing starting room}
  END;                            {Read_Instructions}


  {Set_Token_Parameters}

  PROCEDURE Set_Token_Parameters;
  VAR i : Token;

  BEGIN
    FOR i := AtLocation TO DoneWithTurn
    DO P[i] := 1;                 {set all parameter values to 1}

    {Now deal with exceptions, i.e., parameter values of 0 and 2}

    {*************************************************************************}
    {*                C O N D I T I O N    T O K E N S                       *}
    {*************************************************************************}

    {**********************   PLAYER CONDITIONS   ****************************}
    {                 Type of   Number Of}
    {TOKEN NAME     Parameters Parameters     Explanation}
    {=============== =============  ==== ====================================}
    P[IsCarryingSomething {None} ] := 0; {Player is carrying something}
    P[IsCarryingNothing {None} ] := 0; {Player is carrying nothing}
    {worth at least PTS# points}
    P[IsWearingSomething {None} ] := 0; {Player is wearing something}
    P[IsWearingNothing {None} ] := 0; {Player is wearing nothing}
    P[FirstVisitToRoom {None} ] := 0; {Player is in current room for first time}
    P[NewLife {None} ] := 0;      {Player is starting game or has just been resurrected}

    {**********************   ITEM CONDITIONS   **********************************}
    {                 Type of   Number Of}
    {TOKEN NAME     Parameters Parameters     Explanation}
    {=============== =============  ==== ========================================}
    P[IsLocated {ITEM#  loc#} ] := 2; {ITEM# is located in room loc#}
    P[Together {ITEM# ITEM#} ] := 2; {ITEM# and ITEM# are in same place}

    {*********************   NOUN CONDITIONS   *******************************}
    {                 Type of   Number Of}
    {TOKEN NAME     Parameters Parameters     Explanation}
    {=============== =============  ==== ====================================}
    P[NOUNPresent {none} ] := 0;  {NOUN ITEM is in room, carried or worn}
    P[NOUNIsWearing {none} ] := 0; {NOUN ITEM is being worn}
    P[NOUNIsCarrying {none} ] := 0; {NOUN ITEM is being carried}
    P[NOUNIsNowhere {none} ] := 0; {NOUN ITEM is located NOWHERE (room 0)}
    P[NOUNIsSomewhere {none} ] := 0; {NOUN ITEM is located somewhere}
    P[NOUNInRoom {none} ] := 0;   {NOUN ITEM is located in current room}
    P[NOUNIsON {none} ] := 0;     {NOUN ITEM is ON}
    P[NOUNIsOFF {none} ] := 0;    {NOUN ITEM is OFF}
    P[NOUNIsOpen {none} ] := 0;   {NOUN ITEM is Open}
    P[NOUNIsClosed {none} ] := 0; {NOUN ITEM is Closed}
    P[NOUNIsLocked {none} ] := 0; {NOUN ITEM is Locked}
    P[NOUNIsUnLocked {none} ] := 0; {NOUN ITEM is UnLocked}
    P[NOUNIsEdible {none} ] := 0; {NOUN ITEM is Edible}
    P[NOUNIsDrinkable {none} ] := 0; {NOUN ITEM is Drinkable}
    P[NOUNIsPoisonous {none} ] := 0; {NOUN ITEM is Poisonous}
    P[NOUNIsMovable {none} ] := 0; {NOUN ITEM is Movable}

    {*****************   MISCELLANEOUS CONDITIONS   **************************}
    {                 Type of   Number Of}
    {TOKEN NAME     Parameters Parameters     Explanation}
    {=============== =============  ==== ====================================}
    P[LightPresent {none} ] := 0; {Room has necessary light}
    P[RoomNeedsLight {none} ] := 0; {Room needs a light}
    P[AnswerIsCorrect {none} ] := 0; {last answer was correct}
    P[AnswerIsWrong {none} ] := 0; {last answer was wrong}
    P[CounterEquals {ctr# num} ] := 2; {Counter # is equal to num}
    P[CounterGT {ctr# num} ] := 2; {Counter # is greater than num}
    P[CounterLT {ctr# num} ] := 2; {Counter # is less than num}
    P[VariableEquals {var# num} ] := 2; {Variable # is equal to num}
    P[VariableGT {var# num} ] := 2; {Variable # is greater than num}
    P[VariableLT {var# num} ] := 2; {Variable # is less than num}
    P[CompareVariables {V1 V2} ] := 2; {TRUE if V1 < V2 }
    P[VariableChance {V N} ] := 2; {TRUE if V < Random(1..N)}
    P[NamePresent {none} ] := 0;  {TRUE if Name being addressed is at location or No Name addressed}
    P[PromptForYES {none} ] := 0; {Prompts for Y or N -- Ok if Yes}
    P[PromptForNO {none} ] := 0;  {Prompts for Y or N -- Ok if No}
    P[VerbIsDirection {none} ] := 0; {Verb is movement or direction}
    P[NounIsCreature] := 0;       {TRUE if noun is a creature}
    P[ObjectIsCreature] := 0;     {TRUE if object is a creature}
    P[ObjectPresent] := 0;        {TRUE if object is present in room}
    P[LogicalNOT {none} ] := 0;   {Logical NOT of current condition}
    P[LogicalOR {none} ] := 0;    {Logical OR of conditions}

    {*************************************************************************}
    {*                    A C T I O N     T O K E N S                        *}
    {*************************************************************************}

    {******************* PLAYER ACTION TOKENS ********************************}
    {                 Type of   Number Of}
    {TOKEN NAME     Parameters Parameters     Explanation}
    {=============== =============  ==== ====================================}
    P[GoToRandomRoom {R1 R2} ] := 2; {Send player to Room >= R1 and <= R2}
    P[SendToVariableRoom] := 2;   {Item# Var# -- will send Item# to room number Var#}
    P[GetNOUN {none} ] := 0;      {NOUN is now being carried}
    P[WearNOUN {none} ] := 0;     {NOUN is now being worn}
    P[DropNOUN {none} ] := 0;     {Drops NOUN into current room}
    P[RemoveNOUN {none} ] := 0;   {Removes NOUN and drops into room}
    P[DropEverything {none} ] := 0; {Drop all items being carried}
    P[RemoveEverything {none} ] := 0; {Remove all items being worn}
    P[KillPlayer {none} ] := 0;   {Makes player dead}

    {************** ITEM/NOUN/LOCATION ACTION TOKENS *************************}
    {                 Type of   Number Of}
    {TOKEN NAME     Parameters Parameters     Explanation}
    {=============== =============  ==== ====================================}
    P[PutNOUNInCurrentRoom {none} ] := 0; {Put NOUN in current room}
    P[SendToRoom {ITEM# loc#} ] := 2; {Put ITEM# in room loc#}
    P[SendTreasuresToRoom {loc# pts#} ] := 2; {Send all carried ITEMs whose}
    {points > pts# to loc#}
    P[RelocateAll {loc1 loc2} ] := 2; {Move all items at loc1 to loc2}
    P[DestroyNOUN {none} ] := 0;  {NOUN is now NOWHERE (room 0)}
    P[SwapLocations {ITEM1 ITEM2} ] := 2; {swap locations of ITEM1 & ITEM2}
    P[SendToItem {ITEM1 ITEM2} ] := 2; {Put ITEM1 in location of ITEM2}
    P[ReDirectTo] := 0;           {Re-Direct command to different VERB-NOUN-OBJECT}
    P[RandomMessage] := 2;        {Select message between Num1 and Num2 and print it}
    P[OpenNOUN {none} ] := 0;     {NOUN is now open}
    P[CloseNOUN {none} ] := 0;    {NOUN is now closed}
    P[LockNOUN {none} ] := 0;     {NOUN is now locked}
    P[UnlockNOUN {none} ] := 0;   {NOUN is now unlocked}

    {**************** MISCELLANEOUS ACTION TOKENS ****************************}
    {                 Type of   Number Of}
    {TOKEN NAME     Parameters Parameters     Explanation}
    {=============== =============  ==== ====================================}
    P[ShowScore {none} ] := 0;    {Show current SCORE}
    P[ShowInventory {none} ] := 0; {Show current INVENTORY}
    P[WaitForReturn {none} ] := 0; {Prints 'Hit RETURN' message}
    P[TimePasses {none} ] := 0;   {Show 'Time passes...' message}
    P[CLEARSCREEN {none} ] := 0;  {Clears screen}
    P[LookAtRoom {none} ] := 0;   {Cause a VERBOSE look at room}
    P[BlankLine {none} ] := 0;    {Prints a blank line}
    P[Tone {H M} ] := 2;          {makes a sound at H hertz for M milliseconds}
    P[GetNumberInput {num1 num2} ] := 2; {Prompt for player to input a number}
    {where num1 <= number <= num2}
    {if num1=num2, then no range will be given in prompt}
    P[ChangePassageway {dir# loc#} ] := 2; {Creates or closes a passageway}
    {from current_room to loc# via dir#}
    {dir# = 1 = north ... 12 = exit}
    P[SetVariableTo {var# num#} ] := 2; {Set Variable var# to num#}
    P[AddToVariable {var# num#} ] := 2; {Add num# to Variable var#}
    P[SubtractFromVariable {var# num#} ] := 2; {Subtract num# from Variable #}
    P[AddVariables {V1 V2} ] := 2; {Add V2 to V1 and put answer in V1}
    P[SubtractVariables {V1 V2} ] := 2; {Subtract V2 from V1 and put answer in V1}
    P[RandomVariable {V N} ] := 2; {Set variable V to random number [1 .. N]}
    P[QuitThisCMD {none} ] := 0;  {Quit evaluating this CMD}
    P[QuitAllCMDs {none} ] := 0;  {Finished with all special CMDs}
    P[DoneWithTurn {none} ] := 0; {All Done this turn -- get input next}
    P[WinGame {none} ] := 0;      {Player wins game at end of turn}
    P[EndGame {none} ] := 0;      {game ends at end of turn}
  END;                            {Set_Token_Parameters}

  PROCEDURE MoveIt(ITEMNum, PLACE : Integer);
    {Move ITEMNum to location Place}
    {WARNING -- No condition checking -- Just Move It}
  BEGIN
    IF ITEMNum < First_creature
    THEN BEGIN                    {Adjust count ONLY for Nouns -- NOT for Creatures}
      Adjust_Count(N[ITEMNum]^.location, -1); {reduce count at old location}
      N[ITEMNum]^.location := PLACE; {move it to new Place}
      Detach(ITEMNum);            {make 'position' = none}
      IF PLACE <> Nowhere THEN Adjust_Count(PLACE, 1); {add one to count at new location}
    END
    ELSE M[ITEMNum]^.location := PLACE; {move creature -- don't adjust count}
  END;                            {MoveIt}


  {PERFORM_Special_CMDS(TempVerb,TempNoun,TempObject)}
  {  Perform any Special_CMDs associated with a}
  {  given verb noun object trio, plus 'ANY'}

  PROCEDURE PERFORM_Special_CMDS(VAR TempVerb, TempNoun, TempObject : words);

  LABEL Leave;
  VAR i, J, k, l, CMDnum, Last, num1, num2, loc1, loc2, TestNum, code : Integer;
    Condition, Diag_Mode, OR_Condition, Doing_OR, Prior_Condition : Boolean;
    ReverseCondition, NumOK : Boolean;
    CMDverb, CMDnoun, CMDobject, TempVWord, TempNWord, TempOWord : words;
    TempNameNumber, TempNounNumber, TempObjectNumber : Integer;
    st, st1 : s;
    CurrentToken, NextToken : Token;
    Dir, OpDir : Direction;

    FUNCTION PromptYorN : Char;
    VAR Answer : s;
    BEGIN
      Write(IO, 'Please answer Yes or No: ');
      Answer := GetInputString;
      PromptYorN := Upcase(Answer[1]);
    END;                          {PromptYorN}

    FUNCTION ImmediateLocation(num : Integer) : Integer;
      {Returns immediate location of item}
      {Unlike Global LOCATION which returns location where item is visible}
      {For example, if item is in knapsack which is open and being worn}
      {   ImmediateLocation will return knapsack location number}
      {   Global Location will return wearing number}
    BEGIN
      IF (num >= First_noun) AND (num <= MaxNoun)
      THEN ImmediateLocation := N[num]^.location ELSE
        IF (num >= First_creature) AND (num <= MaxCreature)
        THEN ImmediateLocation := M[num]^.location ELSE
          ImmediateLocation := 0;
    END;                          {ImmediateLocation}

    FUNCTION OppositeDirection(Dir : Direction) : Direction;
    VAR Ans : Direction;
    BEGIN
      Ans := NORTH;
      IF Dir = NORTH THEN Ans := SOUTH ELSE
        IF Dir = SOUTH THEN Ans := NORTH ELSE
          IF Dir = EAST THEN Ans := WEST ELSE
            IF Dir = WEST THEN Ans := EAST ELSE
              IF Dir = northeast THEN Ans := southwest ELSE
                IF Dir = northwest THEN Ans := southeast ELSE
                  IF Dir = southwest THEN Ans := northeast ELSE
                    IF Dir = southeast THEN Ans := northwest ELSE
                      IF Dir = up THEN Ans := down ELSE
                        IF Dir = down THEN Ans := up ELSE
                          IF Dir = enter THEN Ans := Exit ELSE
                            IF Dir = Exit THEN Ans := enter;
      OppositeDirection := Ans;
    END;                          {OppositeDirection}

  BEGIN                           {PERFORM_Special_CMDS}
    i := Verb_Number(TempVerb);
    IF NameNum <> 0
    THEN BEGIN
      i := NameNum;               {use Name as sort key}
      NameNum := TempNameNum;     {Restore NameNum to correct creature number}
    END;
    Diag_Mode := Flag[0];         {can be turned on and off by entering commands}
    IF Diag_Mode THEN BEGIN
      WriteLn(IO, 'For  Verb"', TempVerb, '"  Noun "', TempNoun, '"  Object "',
              TempObject, '"');
      WriteLn(IO, 'For  Verb# or Name#=', i, '  Noun#=', NounNumber, '  Object#=',
              ObjectNumber);
    END;
    Last := EndingIndex[i];       {last in range of Special commands to perform}
    CMDnum := StartingIndex[i]-1;
    IF Diag_Mode THEN WriteLn(IO, 'Verb#= ', i, '  StartIndex= ', StartingIndex[i], ' EndIndex= ',
                              EndingIndex[i]);
    IF Last < 0 THEN GOTO Leave;  {exit if no Special CMDs for this verb}
    IF CMDnum > Last_CMD THEN CMDnum := Last_CMD; {Restrict CMDnum to 0..Last_CMD}
    IF CMDnum < 0 THEN CMDnum := 0;
    REPEAT                        {Until CMDnum = Last}
      CMDnum := CMDnum+1;
      i := SpecialCMD[CMDnum]^.VerbNum; {get verb number for this CMD}
      {if i >= 2000 then this command is just data for prior command}
      CMDverb := SpecialCMD[CMDnum]^.VerbCMD; {get verb for this CMD}
      CMDnoun := SpecialCMD[CMDnum]^.NounCMD; {get noun for this CMD}
      CMDobject := SpecialCMD[CMDnum]^.ObjectCMD; {get object for this CMD}
      IF (((TempVerb = CMDverb) OR (CMDverb = 'ANY')) AND
          ((TempNoun = CMDnoun) OR (CMDnoun = 'ANY')) AND
          ((TempObject = CMDobject) OR (CMDobject = 'ANY')) AND (i < 2000)) THEN
        BEGIN                     {OK to execute this Special CMD}
          IF Diag_Mode THEN
            BEGIN
              WriteLn(IO, ' ');
              WriteLn(IO, 'Considering CMD #', CMDnum, ' ', CMDverb, ' ', CMDnoun, ' ', CMDobject);
            END;
          J := 1;                 {index into SpecialCMD.data array}
          Condition := True;
          OR_Condition := False;
          Doing_OR := False;
          WHILE Condition DO
            BEGIN
              loc1 := SpecialCMD[CMDnum]^.Data[J]; {token number}
              CurrentToken := Token(SpecialCMD[CMDnum]^.Data[J]);
              IF CurrentToken = LogicalNOT THEN
                BEGIN
                  ReverseCondition := True;
                  IF Diag_Mode THEN Write(IO, 'NOT ');
                  J := J+1;
                  loc1 := SpecialCMD[CMDnum]^.Data[J]; {token number}
                  CurrentToken := Token(SpecialCMD[CMDnum]^.Data[J]);
                END
              ELSE ReverseCondition := False;
              loc2 := P[CurrentToken]; {number of parameters}
              IF loc2 > 0 THEN
                num1 := SpecialCMD[CMDnum]^.Data[J+1]; {get first parameter}
              IF loc2 > 1 THEN
                num2 := SpecialCMD[CMDnum]^.Data[J+2]; {get second parameter}
              {may not use these -- but it saves code to get them here}
              IF Diag_Mode THEN
                BEGIN
                  Write(IO, 'Token #', loc1, ' ', loc2, ' parameters ');
                  IF (loc2 > 0) THEN Write(IO, num1, ' ');
                  IF (loc2 > 1) THEN Write(IO, num2, ' ');
                  WriteLn(IO, ' ');
                END;
              CASE CurrentToken OF
                {**************************************}
                {*  C O N D I T I O N    T O K E N S  *}
                {**************************************}
                VerbIsDirection {none} {Global Verb (NOT "ANY") is direction}
                : Condition := Is_Direction(verb);
                NounIsCreature    {TRUE if noun is a creature}
                : Condition := Is_Creature(noun);
                ObjectIsCreature  {TRUE if object is a creature}
                : Condition := Is_Creature(object_word);
                ObjectPresent     {TRUE if object is present in room}
                : Condition := (Is_Visible(ObjectNumber));
                AtLocation {loc#} {Player is located at room loc#}
                : Condition := (Current_room = num1);
                AtLocationGT {loc#} {In room greater than loc#}
                : Condition := (Current_room > num1);
                AtLocationLT {loc#} {In room less than loc#}
                : Condition := (Current_room < num1);
                FirstVisitToRoom {None} {Player is in current room for first time}
                : Condition := FirstVisitFlag;
                NewLife {None}    {Player is starting game or has just been resurrected}
                : Condition := NewLifeFlag;
                IsCarryingSomething {None} {Player is carrying something}
                : Condition := (Items_Being_Carried > 0);
                IsCarryingNothing {None} {Player is carrying nothing}
                : Condition := (Items_Being_Carried < 1);
                IsCarryingTreasure {PTS#} {Player is carrying something}
                {worth at least PTS#}
                : BEGIN
                    Condition := False;
                    FOR num2 := First_noun TO MaxNoun DO
                      IF (ImmediateLocation(num2) = Player) AND (N[num2]^.points >= num1)
                      THEN Condition := True;
                  END;
                IsWearingSomething {None} {Player is wearing something}
                : Condition := (Items_Being_Worn > 0);
                IsWearingNothing {None} {Player is wearing nothing}
                : Condition := (Items_Being_Worn < 1);
                LoadWeightEquals {num#} {Load weighs equals}
                : Condition := (Load_Weight = num1);
                LoadWeightGT {num#} {Load weighs more than num#}
                : Condition := (Load_Weight > num1);
                LoadWeightLT {num#} {Load weighs less than num#}
                : Condition := (Load_Weight < num1);
                Present {ITEM#}   {ITEM is in room, carried or worn}
                : Condition := (Is_Visible(num1));
                IsWearing {ITEM#} {ITEM is being worn}
                : Condition := (location(num1) = Wearing);
                IsCarrying {ITEM#} {ITEM is being carried}
                : Condition := (location(num1) = Player);
                IsNowhere {ITEM#} {ITEM is located NOWHERE (room 0)}
                : Condition := (location(num1) = Nowhere);
                IsSomewhere {ITEM#} {ITEM is located somewhere}
                : Condition := NOT(location(num1) = Nowhere);
                InRoom {ITEM#}    {ITEM is located in current room}
                : Condition := (location(num1) = Current_room);
                IsLocated {ITEM# loc#} {ITEM# is located in room loc#}
                : Condition := (ImmediateLocation(num1) = num2);
                Together {ITEM# ITEM#} {ITEM# and ITEM# are in same room}
                : Condition := (location(num1) = location(num2));
                IsON {ITEM#}      {ITEM is ON}
                : Condition := N[num1]^.on;
                IsOFF {ITEM#}     {ITEM is OFF}
                : Condition := NOT N[num1]^.on;
                IsGroupMember {ITEM#} {ITEM is a member of the group}
                : Condition := M[num1]^.groupmember;
                IsOpen {ITEM#}    {ITEM is Open}
                : Condition := N[num1]^.open;
                IsClosed {ITEM#}  {ITEM is Closed}
                : Condition := NOT N[num1]^.open;
                IsLocked {ITEM#}  {ITEM is Locked}
                : Condition := N[num1]^.locked;
                IsUnLocked {ITEM#} {ITEM is UnLocked}
                : Condition := NOT N[num1]^.locked;
                IsEdible {ITEM#}  {ITEM is Edible}
                : Condition := N[num1]^.edible;
                IsDrinkable {ITEM#} {ITEM is Drinkable}
                : Condition := N[num1]^.drinkable;
                IsPoisonous {ITEM#} {ITEM is Poisonous}
                : Condition := N[num1]^.poisonous;
                IsMovable {ITEM#} {ITEM is Movable}
                : Condition := N[num1]^.movable;
                NOUNPresent {none} {NOUN is in room, carried or worn}
                : Condition := (Is_Visible(NounNumber));
                NOUNIsWearing {none} {NOUN is being worn}
                : Condition := (location(NounNumber) = Wearing);
                NOUNIsCarrying {none} {NOUN is being carried}
                : Condition := (location(NounNumber) = Player);
                NOUNIsNowhere {none} {NOUN ITEM is located NOWHERE (room 0)}
                : Condition := (location(NounNumber) = Nowhere);
                NOUNIsSomewhere {none} {NOUN ITEM is located somewhere}
                : Condition := NOT(location(NounNumber) = Nowhere);
                NOUNInRoom {none} {NOUN ITEM is located in current room}
                : Condition := (location(NounNumber) = Current_room);
                NOUNIsLocated {loc#} {NOUN ITEM is located in room loc#}
                : Condition := (ImmediateLocation(NounNumber) = num1);
                NOUNIsON {none}   {NOUN ITEM is ON}
                : Condition := N[NounNumber]^.on;
                NOUNIsOFF {none}  {NOUN ITEM is OFF}
                : Condition := NOT N[NounNumber]^.on;
                NOUNIsOpen {none} {NOUN ITEM is Open}
                : Condition := N[NounNumber]^.open;
                NOUNIsClosed {none} {NOUN ITEM is Closed}
                : Condition := NOT N[NounNumber]^.open;
                NOUNIsLocked {none} {NOUN ITEM is Locked}
                : Condition := N[NounNumber]^.locked;
                NOUNIsUnLocked {none} {NOUN ITEM is UnLocked}
                : Condition := NOT N[NounNumber]^.locked;
                NOUNIsEdible {none} {NOUN ITEM is Edible}
                : Condition := N[NounNumber]^.edible;
                NOUNIsDrinkable {none} {NOUN ITEM is Drinkable}
                : Condition := N[NounNumber]^.drinkable;
                NOUNIsPoisonous {none} {NOUN ITEM is Poisonous}
                : Condition := N[NounNumber]^.poisonous;
                NOUNIsMovable {none} {NOUN ITEM is Movable}
                : Condition := N[NounNumber]^.movable;
                NOUNpointsEquals {num#} {NOUN points equal num#}
                : Condition := (N[NounNumber]^.points = num1);
                NOUNpointsGT {num#} {NOUN points are greater than num#}
                : Condition := (N[NounNumber]^.points > num1);
                NOUNpointsLT {num#} {NOUN points are less than num#}
                : Condition := (N[NounNumber]^.points < num1);
                NOUNweightEquals {num#} {NOUN weight equals num#}
                : Condition := (N[NounNumber]^.weight = num1);
                NOUNweightGT {num#} {NOUN weight is greater than num#}
                : Condition := (N[NounNumber]^.weight > num1);
                NOUNweightLT {num#} {NOUN weight is less than num#}
                : Condition := (N[NounNumber]^.weight < num1);
                LightPresent {none} {Room has necessary light}
                : Condition := LightIsHere;
                RoomNeedsLight {none} {Current room needs a light}
                : Condition := (Room[Current_room]^.light > 0);
                FlagON {flag#}    {Flag# is ON}
                : Condition := Flag[num1];
                FlagOFF {flag#}   {Flag# is OFF}
                : Condition := NOT Flag[num1];
                ScoreEquals {num} {current score is equal to num}
                : Condition := (ScoreValue = num1);
                ScoreGT {num}     {score is greater than num}
                : Condition := (ScoreValue > num1);
                ScoreLT {num}     {score is less than num}
                : Condition := (ScoreValue < num1);
                NumberEquals {num} {input number is equal to num}
                : Condition := (NumberInput = num1);
                NumberGT {num}    {number is greater than num}
                : Condition := (NumberInput > num1);
                NumberLT {num}    {number is less than num}
                : Condition := (NumberInput < num1);
                AnswerIsCorrect {num} {last answer was correct}
                : Condition := QuestionStatus;
                AnswerIsWrong {num} {last answer was wrong}
                : Condition := NOT QuestionStatus;
                TurnsEquals {num} {Turns score is equal to num}
                : Condition := (Num_turns = num1);
                TurnsGT {num}     {Turns is greater than num}
                : Condition := (Num_turns > num1);
                TurnsLT {num}     {Turns is less than num}
                : Condition := (Num_turns < num1);
                CounterEquals {ctr# num} {Counter # is equal to num}
                : Condition := (counter[num1] = num2);
                CounterGT {ctr# num} {Counter # is greater than num}
                : Condition := (counter[num1] > num2);
                CounterLT {ctr# num} {Counter # is less than num}
                : Condition := (counter[num1] < num2);
                VariableEquals {var# num} {Variable # is equal to num}
                : Condition := (Variable[num1] = num2);
                VariableGT {var# num} {Variable # is greater than num}
                : Condition := (Variable[num1] > num2);
                VariableLT {var# num} {Variable # is less than num}
                : Condition := (Variable[num1] < num2);
                CompareVariables  {TRUE if V1 < V2 }
                : Condition := (Variable[num1] < Variable[num2]);
                VariableChance    {TRUE if V < Random(1..N)}
                : Condition := (Variable[num1] < Random(num2+1));
                NamePresent       {TRUE if Name being addressed is at location}
                : Condition := ((NameNum <> 0) AND (Is_Visible(NameNum)));
                NameIsNumber      {TRUE if Name being addressed is Number num1}
                : Condition := (NameNum = num1);
                NOUNIsNumber      {TRUE if NOUN is Number num}
                : Condition := (NounNumber = num1);
                ObjectIsNumber    {TRUE if Object is Number num}
                : Condition := (ObjectNumber = num1);
                SomethingInside   {TRUE if there is something inside Object Num}
                : Condition := (Things_Here(num1) > 0);
                Chance {percent}  {Odds are percent, i.e. 10 %}
                : Condition := (Random(100) < num1);
                PromptForYES {none} {Prompts for Y or N -- Ok if Yes}
                : Condition := (PromptYorN = 'Y');
                PromptForNO {none} {Prompts for Y or N -- Ok if No}
                : Condition := (PromptYorN = 'N');
                {**************************************}
                {*     A C T I O N    T O K E N S     *}
                {**************************************}
                {**************************************}
                {*  ******   W A R N I N G   *******  *}
                {*  Unless otherwised noted -- NONE   *}
                {*  of these actions are accompanied  *}
                {*  by any messages or condition      *}
                {*  checking --- the action is        *}
                {*  just taken without any 'fanfare'. *}
                {*  If you want a message of some kind*}
                {*  you must print it yourself.       *}
                {*  If you want to check on the       *}
                {*  feasiblity of the action, (e.g.,  *}
                {*  an ITEM is in the room you must   *}
                {*  check it yourself.                *}
                {**************************************}
                QuitThisCMD {none} {Quit evaluating this CMD}
                : Condition := False;
                QuitAllCMDs {none} {Finished with all special CMDs}
                : BEGIN
                    Condition := False;
                    CMDnum := Last; {will exit from procedure}
                  END;
                DoneWithTurn {none} {All Done this turn -- get new input}
                : BEGIN
                    Condition := False;
                    CMDnum := Last; {will exit from procedure}
                    DoNormalCMD := False; {will skip remainder of this turn}
                  END;
                GoToRoom {loc#}   {Send player to loc#}
                : BEGIN
                    MoveGroup(Current_room, num1); {move group}
                    Current_room := num1;
                  END;
                GoToRandomRoom {R1 R2} {Send player to Room >= R1 and <= R2}
                : BEGIN
                    k := Current_room;
                    REPEAT
                      l := Random(num2-num1+1);
                      k := num1+l;
                    UNTIL k <> Current_room;
                    {make sure Random Room is different than Current Room}
                    MoveGroup(Current_room, k); {move group}
                    Current_room := k;
                  END;
                GetIt {ITEM#}     {ITEM# is now being carried}
                : MoveIt(num1, Player);
                WearIt {ITEM#}    {ITEM# is now being worn}
                : MoveIt(num1, Wearing);
                DropIt {ITEM#}    {Drops ITEM# into current room}
                : MoveIt(num1, Current_room);
                RemoveIt {ITEM#}  {Removes ITEM and drops into room}
                : MoveIt(num1, Current_room);
                GetNOUN {none}    {NOUN is now being carried}
                : MoveIt(NounNumber, Player);
                WearNOUN {none}   {NOUN is now being worn}
                : MoveIt(NounNumber, Wearing);
                DropNOUN {none}   {Drops NOUN into current room}
                : MoveIt(NounNumber, Current_room);
                RemoveNOUN {none} {Removes NOUN and drops into room}
                : MoveIt(NounNumber, Current_room);
                DropEverything {none} {Drop all items being carried}
                : FOR num1 := First_noun TO MaxNoun DO
                    IF ImmediateLocation(num1) = Player
                    THEN MoveIt(num1, Current_room);
                RemoveEverything {none} {Remove all items being worn}
                : FOR num1 := First_noun TO MaxNoun DO
                    IF ImmediateLocation(num1) = Wearing
                    THEN MoveIt(num1, Current_room);
                KillPlayer {none} {Makes player dead, exit and finish turn}
                : BEGIN
                    player_dead := True;
                    Condition := False;
                    CMDnum := Last; {will exit from procedure}
                    DoNormalCMD := False; {will skip remainder of this turn}
                  END;
                PutInCurrentRoom {ITEM#} {Put ITEM# in current room}
                : MoveIt(num1, Current_room);
                SendToRoom {ITEM# loc#} {Put ITEM# in room loc#}
                : MoveIt(num1, num2);
                PutNOUNInCurrentRoom {none} {Put NOUN in current room}
                : MoveIt(NounNumber, Current_room);
                SendNOUNToRoom {loc#} {Put NOUN in room loc#}
                : MoveIt(NounNumber, num1);
                SendAllToRoom, {loc#} {Send all carried ITEMs to loc#}
                SendTreasuresToRoom {loc# pts#} {Send all carried ITEMs whose}
                {points > pts# to loc#}
                : BEGIN
                    IF CurrentToken = SendAllToRoom
                    THEN loc2 := -1
                    ELSE loc2 := num2;
                    FOR num2 := First_noun TO MaxNoun DO
                      IF (ImmediateLocation(num2) = Player) AND (N[num2]^.points > loc2)
                      THEN MoveIt(num2, num1);
                  END;
                RelocateAll {loc1 loc2} {Move all items at loc1 to loc2}
                : FOR loc2 := First_noun TO MaxNoun DO
                    IF ImmediateLocation(loc2) = num1
                    THEN MoveIt(loc2, num2);
                Destroy {ITEM#}   {ITEM# is now NOWHERE (room 0)}
                : MoveIt(num1, Nowhere);
                DestroyNOUN {none} {NOUN is now NOWHERE (room 0)}
                : MoveIt(NounNumber, Nowhere);
                SwapLocations {ITEM1 ITEM2} {swap locations of ITEM1 & ITEM2}
                : BEGIN
                    loc1 := ImmediateLocation(num1);
                    loc2 := ImmediateLocation(num2);
                    MoveIt(num1, loc2);
                    MoveIt(num2, loc1);
                  END;
                SendToItem {ITEM1 ITEM2} {Put ITEM1 in location of ITEM2}
                : BEGIN
                    loc2 := ImmediateLocation(num2);
                    MoveIt(num1, loc2);
                  END;
                SendNOUNToItem {ITEM} {Put NOUN in location of ITEM}
                : BEGIN
                    loc1 := ImmediateLocation(num1);
                    MoveIt(NounNumber, loc1);
                  END;
                AddToGroup {Itme#} {Add item# to group}
                : M[num1]^.groupmember := True;
                RemoveFromGroup {Itme#} {Remove item# from group}
                : M[num1]^.groupmember := False;
                MoveTheGroup {loc#} {Send group to loc#}
                : MoveGroup(Current_room, num1); {move group -- NOT the player}
                ReDirectTo        {Re-direct to another VERB-NOUN-OBJECT}
                : BEGIN
                    TempNameNumber := NameNum;
                    TempNounNumber := NounNumber;
                    TempObjectNumber := ObjectNumber;
                    CMDnum := CMDnum+1; {advance to next command to get data}
                    i := SpecialCMD[CMDnum]^.VerbNum-2000;
                    {get verb num being redirected to}
                    TempVWord := SpecialCMD[CMDnum]^.VerbCMD; {get redirected verb}
                    TempNWord := SpecialCMD[CMDnum]^.NounCMD; {get redirected noun}
                    TempOWord := SpecialCMD[CMDnum]^.ObjectCMD; {get redirected object}
                    {Now check for Verb being ReDirected to $VERB$, $NOUN$, OBJECT$, or $NAME$}
                    IF TempVWord = 'VERB' THEN TempVWord := TempVerb
                    ELSE IF TempVWord = 'NOUN' THEN TempVWord := TempNoun
                    ELSE IF TempNWord = 'OBJECT' THEN
                      BEGIN
                        TempNWord := TempObject;
                        TempNounNumber := ObjectNumber;
                      END
                    ELSE IF TempVWord = 'NAME' THEN
                      BEGIN
                        TempVWord := NameStr;
                        Capitalize(TempVWord);
                      END;
                    {Now check for Noun being ReDirected to $VERB$, $NOUN$, OBJECT$, or $NAME$}
                    IF TempNWord = 'VERB' THEN TempNWord := TempVerb
                    ELSE IF TempNWord = 'NOUN' THEN TempNWord := TempNoun
                    ELSE IF TempNWord = 'OBJECT' THEN TempNWord := TempObject
                    ELSE IF TempNWord = 'NAME' THEN
                      BEGIN
                        TempNWord := NameStr;
                        TempNounNumber := NameNum;
                        Capitalize(TempNWord);
                      END;
                    {Now check for Object being ReDirected to $VERB$, $NOUN$, OBJECT$, or $NAME$}
                    IF TempOWord = 'VERB' THEN TempOWord := TempVerb
                    ELSE IF TempOWord = 'NOUN' THEN
                      BEGIN
                        TempOWord := TempNoun;
                        TempObjectNumber := NounNumber;
                      END
                    ELSE IF TempOWord = 'OBJECT' THEN TempOWord := TempObject
                    ELSE IF TempOWord = 'NAME' THEN
                      BEGIN
                        TempOWord := NameStr;
                        TempObjectNumber := NameNum;
                        Capitalize(TempOWord);
                      END;
                    TempVerb := TempVWord; {Finally do redirection}
                    TempNoun := TempNWord;
                    TempObject := TempOWord;
                    NameNum := TempNameNumber; {Map various numbers also}
                    NounNumber := TempNounNumber;
                    ObjectNumber := TempObjectNumber;
                    CMDnum := StartingIndex[i]-1; {new starting index}
                    Last := EndingIndex[i]; {new ending index}
                    IF Last < 0 THEN GOTO Leave; {exit if no Special CMDs for this verb}
                    IF CMDnum > Last_CMD THEN CMDnum := Last_CMD; {Restrict CMDnum to 0..Last_CMD}
                    IF CMDnum < 0 THEN CMDnum := 0;
                    Condition := False; {finish processing this command}
                    Doing_OR := False;
                    IF Diag_Mode THEN
                      BEGIN
                        WriteLn(IO, 'Re-Directing to ', TempVerb, ' ', TempNoun, ' ', TempObject);
                        WriteLn(IO, 'Verb# = ', i, '  Start = ', StartingIndex[i], '  End = ', Last);
                      END;
                  END;
                RandomMessage     {num1 num2}
                {Randomly select message between num1 and num2 and print it}
                : BEGIN
                    num2 := Random(num2-num1+1);
                    num1 := num1+num2;
                    Describe_It('MESSAGE', num1);
                  END;
                ShowContents      {Display list of things inside Object Num}
                : List_Contents(num1, 1);
                OpenIt {ITEM}     {ITEM# is now open}
                : N[num1]^.open := True;
                CloseIt {ITEM}    {ITEM# is now closed}
                : N[num1]^.open := False;
                LockIt {ITEM}     {ITEM# is now locked}
                : N[num1]^.locked := True;
                UnlockIt {ITEM}   {ITEM# is now unlocked}
                : N[num1]^.locked := False;
                OpenNOUN {none}   {NOUN is now open}
                : N[NounNumber]^.open := True;
                CloseNOUN {none}  {NOUN is now closed}
                : N[NounNumber]^.open := False;
                LockNOUN {none}   {NOUN is now locked}
                : N[NounNumber]^.locked := True;
                UnlockNOUN {none} {NOUN is now unlocked}
                : N[NounNumber]^.locked := False;
                ShowScore {none}  {Show current SCORE}
                : show_score;
                PlusScore {num}   {Add num to current SCORE}
                : ScoreAdjustment := ScoreAdjustment+num1;
                MinusScore {num}  {Subtract num from current SCORE}
                : ScoreAdjustment := ScoreAdjustment-num1;
                ShowInventory {none} {Show current INVENTORY}
                : Inventory;
                WaitForReturn {none} {Prints 'Hit RETURN' message}
                : Pause;
                TimePasses {none} {Show 'Time passes...' message}
                : Do_Nothing;
                xDelay {num}      {Delay for num seconds}
                : DELAY(1000*num1);
                CLEARSCREEN {none} {Clears screen}
                : BEGIN
                    CLRSCR;
                    morecount := 0;
                  END;
                DescribeThing {num} {Describe thing num (whatever)}
                : BEGIN
                    IF (num1 >= First_Room) AND (num1 <= MaxRoom)
                    THEN Describe_It('ROOM_DESCR', num1);
                    IF (num1 >= First_noun) AND (num1 <= MaxNoun)
                    THEN Describe_It('NOUN_DESCR', num1);
                    IF (num1 >= First_creature) AND (num1 <= MaxCreature)
                    THEN Describe_It('CREATURE_DESCR', num1);
                  END;
                LookAtRoom {none} {Cause a VERBOSE look at room}
                :
                  BEGIN
                    Room[Current_room]^.has_seen := False;
                    Previous_room := -1;
                    Describe_scene;
                  END;
                WinGame {none}    {Player wins game at end of turn}
                : Room[Current_room]^.game_win := True;
                EndGame {none}    {game ends at end of turn}
                : Room[Current_room]^.game_end := True;
                PrintMessage {num} {Prints message num}
                : Describe_It('MESSAGE', num1);
                BlankLine {none}  {Prints Blank Line}
                : BEGIN
                    WriteLn(IO, ' ');
                    morecount := morecount+1;
                  END;
                Tone {H M}        {makes a sound at H hertz for M milliseconds}
                : BEGIN
                    Sound(num1);
                    DELAY(num2);
                    NoSound;
                  END;
                GetNumberInput {num1 num2} {Get input num1 <= input <= num2}
                : BEGIN
                    REPEAT
                      NumOK := False;
                      Write(IO, 'What number');
                      IF num1 = num2
                      THEN Write(IO, ' ? ')
                      ELSE Write(IO, ' (from ', num1, ' to ', num2, ') ? ');
                      st := GetInputString;
                      TestNum := Value(st);
                      IF num1 = num2
                      THEN NumOK := True
                      ELSE IF ((TestNum >= num1) AND (TestNum <= num2))
                      THEN NumOK := True;
                    UNTIL NumOK;
                    NumberInput := TestNum;
                  END;
                AskQuestion {num} {ask question num and set QuestionStatus}
                : BEGIN
                    QuestionStatus := False;
                    IF ((num1 <= MaxQuestion) AND (Question[num1] <> 'NONE')) THEN
                      BEGIN
                        REPEAT
                          num2 := POS('  ', Answer[num1]);
                          IF (num2 <> 0) THEN Delete(Answer[num1], num2, 1);
                        UNTIL num2 = 0;
                        Answer[num1] := ' '+Answer[num1]+' ';
                        {add single leading and trailing blank}
                        WHILE (POS(' ', Question[num1]) = 1) DO Delete(Question[num1], 1, 1);
                        {strip off leading blanks in question}
                        Write(IO, Question[num1]);
                        st := GetInputString;
                        st := ' '+st+' ';
                        IF (Length(Answer[num1]) <= Length(st))
                        THEN IF (POS(Answer[num1], st) <> 0)
                          THEN QuestionStatus := True;
                        IF (Length(Answer[num1]) >= Length(st))
                        THEN IF (POS(st, Answer[num1]) <> 0)
                          THEN QuestionStatus := True;
                      END;
                  END;
                TurnFlagON {flag#} {Turn Flag# ON}
                : IF num1 <= MaxFlag THEN Flag[num1] := True;
                TurnFlagOFF {flag#} {Turn Flag# OFF}
                : IF num1 <= MaxFlag THEN Flag[num1] := False;
                ToggleFlag {flag#} {Toggle Flag#}
                : IF num1 <= MaxFlag THEN
                    IF Flag[num1]
                    THEN Flag[num1] := False
                    ELSE Flag[num1] := True;
                TurnCounterON {ctr#} {Turn counter# ON -- sets to 1}
                : IF num1 <= MaxCounter THEN counter[num1] := 1;
                TurnCounterOFF {ctr#} {Turn counter# OFF -- sets to 0}
                : IF num1 <= MaxCounter THEN counter[num1] := 0;
                SetVariableTo {var# num#} {Set Variable var# to num#}
                : IF num1 <= MaxVariable THEN Variable[num1] := num2;
                AddToVariable {var# num#} {Add num# to Variable var#}
                : IF num1 <= MaxVariable THEN Variable[num1] := Variable[num1]+num2;
                SubtractFromVariable {var# num#} {Subtract num# from Variable #}
                : IF num1 <= MaxVariable THEN Variable[num1] := Variable[num1]-num2;
                AddVariables {V1 V2} {Add V2 to V1 and put answer in V1}
                : Variable[num1] := Variable[num1]+Variable[num2];
                SubtractVariables {V1 V2} {Subtract V2 from V1 and put answer in V1}
                : Variable[num1] := Variable[num1]-Variable[num2];
                RandomVariable {V N} {Set variable V to random number [1 .. N]}
                : Variable[num1] := Random(num2+1);
                MakeVarRoomNum    {Var# -- will make Var# equal current room number}
                : Variable[num1] := Current_room;
                MakeVarNounNum    {Var# -- will make Var# equal current noun number}
                : Variable[num1] := NounNumber;
                MakeVarObjectNum  {Var# -- will make Var# equal object room number}
                : Variable[num1] := ObjectNumber;
                GoToVariableRoom  {Var# -- will send player to room number Var#}
                : BEGIN
                    MoveGroup(Current_room, Variable[num1]); {move group}
                    Current_room := Variable[num1];
                  END;
                SendToVariableRoom {Item# Var# -- will send Item# to room number Var#}
                : MoveIt(num1, Variable[num2]);
                GetVariableIt     {Var# -- will get Var# item for player}
                : MoveIt(Variable[num1], Player);
                PrintVariableMessage {Var# -- will print message number Var#}
                : Describe_It('MESSAGE', Variable[num1]);
                NounToVariable {var#} {Convert Noun to Variable #}
                : BEGIN
                    Val(TempNoun, num2, code);
                    IF code <> 0 THEN num2 := 0; {If noun is not a number, set var# to 0}
                    Variable[num1] := num2;
                  END;
                ObjectToVariable {var#} {Convert Object to Variable #}
                : BEGIN
                    Val(TempObject, num2, code);
                    IF code <> 0 THEN num2 := 0; {If object is not a number, set var# to 0}
                    Variable[num1] := num2;
                  END;
                ChangePassageway {dir# loc#} {Creates or closes a passageway}
                {from current_room to loc# via dir#}
                {dir# = 1 = north ... 12 = exit}
                {If loc# = 0 then closes passage}
                : IF (num1 > 0) AND (num1 < 13) AND
                  (((num2 >= First_Room) AND (num2 <= MaxRoom)) OR (num2 = 0))
                  THEN BEGIN
                    Dir := Direction(num1-1); {get requested direction}
                    OpDir := OppositeDirection(Dir); {get its opposite}
                    loc1 := Room[Current_room]^.Path[Dir]; {currently linked room}
                    IF Diag_Mode THEN
                      BEGIN
                        WriteLn(IO, 'Direction   = ', Ord(Dir));
                        WriteLn(IO, 'Opposite    = ', Ord(OpDir));
                        WriteLn(IO, 'Target Room = ', num2);
                        WriteLn(IO, 'Linked Room = ', loc1);
                      END;
                    IF num2 = 0
                    THEN BEGIN    {Close passageway at both ends}
                      Room[Current_room]^.Path[Dir] := 0; {Close passageway}
                      IF (loc1 >= First_Room)
                      THEN Room[loc1]^.Path[OpDir] := 0; {Close passageway}
                    END
                    ELSE BEGIN    {open passageway between rooms}
                      Room[Current_room]^.Path[Dir] := num2; {open passage to num2}
                      Room[num2]^.Path[OpDir] := Current_room; {open passage to current room}
                    END;
                  END;
              ELSE                {token case}
                BEGIN
                  num1 := SpecialCMD[CMDnum]^.Data[J];
                  WriteLn(IO, 'ERROR: Illegal Token # ', num1, ' in CMD # ', CMDnum);
                END;
              END;                {token case}
              IF ReverseCondition THEN Condition := NOT Condition; {Apply NOT}
              J := J+P[CurrentToken]+1; {skip past parameters for this token}
              NextToken := Token(SpecialCMD[CMDnum]^.Data[J]);
              IF (Doing_OR) THEN  {Some OR processing required}
                BEGIN
                  Prior_Condition := (Condition AND Prior_Condition);
                  Condition := True; {want to continue unless Action and OR_Cond=FALSE}
                  IF (NextToken > LogicalOR) {i.e., an action} THEN
                    BEGIN         {Action Token ends the OR clause}
                      Condition := (OR_Condition OR Prior_Condition);
                      Doing_OR := False;
                      OR_Condition := False; {in case we have another series of OR's}
                    END;
                END;              {Doing_OR}
              IF (NextToken = LogicalOR) THEN
                BEGIN
                  IF Diag_Mode THEN WriteLn(IO, 'OR');
                  IF (Doing_OR)
                  THEN OR_Condition := (OR_Condition OR Prior_Condition)
                  ELSE OR_Condition := (OR_Condition OR Condition); {first OR}
                  Doing_OR := True;
                  Condition := True; {I.E., we want to continue regardless}
                  Prior_Condition := True; {start with TRUE at each OR}
                  J := J+1;       {want to skip by OR to get next real Token}
                END;              {NextToken = LogicalOR}
            END;                  {WHILE Condition is TRUE}
        END;                      {OF IF --- OK to execute this particular Special CMD}
    UNTIL (CMDnum >= Last) OR (CMDnum >= MaxCommand); {REPEAT thru all Special CMD for Verb}

Leave: {Jumped to if no Special CMDs for this Verb}

  END;                            {PERFORM_Special_CMDS}

